package dk.aau.walkietalkie.network;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
import dk.aau.walkietalkieui.message.MyMessage;
import dk.aau.walkietalkieui.message.MyMessage.MessageType;

@SuppressLint("NewApi")
public class MessageSendingViaNetwork {

	private static final int SENDER_PORT = 8988;
	private static final int RECEIVER_PORT = 8956;
	private static String TAG = "MessageSending";
	private ReceiverThread receiverThread = null;
	private ClientThread clientThread = null;
	// private ClientThread clientThread = new ClientThread();
	private EditText messageToBeSentEditText;
	private String ip;
	private MyMessage msg;

	private static final String FILE_PATH = Environment
			.getExternalStorageDirectory().getAbsolutePath() + "/tmp_text.txt";

	public boolean sendMessageViaNetwork(MyMessage msg) {
		this.msg = msg;
		try {
			clientThread = new ClientThread();
			clientThread.start();
			// clientThread.run();
			clientThread.sleep(50);
			String encoded = msgEncode(msg);
			sendEncodedMessage(encoded);
			// msgEncode(msg);
			return true;
		} catch (Exception e) {
			Log.d("ERROR", "Msg de erro: " + e.getMessage());
		}

		return false;
	}

	private String msgEncode(MyMessage msg) {
		Log.e(TAG, "+++++++++++ encoding message +++++++++++++");
		MessageType msgType = msg.getType();

		switch (msgType) {
		case TYPE_RECORD: {
			// SendAudioFile(msg);
			// sendFile(msg);
			break;
		}
		case TYPE_PICTURE: {
			Log.e(TAG, "+++++ CASE PICTURE +++++++");
			ByteArrayOutputStream stream = new ByteArrayOutputStream();
			byte[] val = stream.toByteArray();
			String ba = Base64.encodeToString(val, Base64.DEFAULT);
			return ba;
			// sendFile(msg);
			// break;
		}
		case TYPE_TEXT: {
			// SendTextFile(msg);
			// sendFile(msg);
			break;
		}

		}
		// TODO
		return ip;

	}

	private void sendEncodedMessage(String encodedMsg) {
		// Write in the socket
		Log.e(TAG, "+++++++++++Sending encoded Message ++++++++++++++ ");
		OutputStream os = clientThread.getOutputStream();
		try {
			if (os != null) {
				Log.e(TAG, "+++++++Write on os +++++++++++++");
				os.write(encodedMsg.getBytes());
				os.flush();
			} else {
				Log.e(TAG, "Socket is closed !!!!");
			}
		} catch (Exception e) {
			Log.d("ERROR", "Msg de erro: " + e.getMessage());
		}

		finally {
			try {
				os.close();
				clientThread.disconnect();
				clientThread.stop();
			} catch (Exception e) {

			}
		}

	}

	public class ClientThread extends Thread {
		private Socket socket;
		public OutputStream os = null;
		private String destination;

		@Override
		public void run() {
			Log.e(TAG, "++++++++++++RUN+++++++++");
			try {
				destination = msg.getDestinyIp();
				Log.e(TAG, "1.Connected to " + destination);
				socket = new Socket(destination, SENDER_PORT);
				if (socket.getOutputStream() == null) {
					os = new OutputStream() {

						@Override
						public void write(int oneByte) throws IOException {
							Log.d(TAG, " OUTPUT WORKING !!!!!");
							// TODO Auto-generated method stub

						}
					};
				} else
					os = socket.getOutputStream();

				Log.e(TAG, "2.Connected to " + destination);

			} catch (UnknownHostException e) {
				// isConnected = false;
				e.printStackTrace();
			} catch (IOException e) {
				// isConnected = false;
				e.printStackTrace();
			}
		}

		public OutputStream getOutputStream() {
			// TODO This.os is null
			Log.e(TAG, "Getting outputstream" + this.os);
			return this.os;
		}

		public void disconnect() {
			try {
				if (socket != null) {
					socket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			socket = null;
		}

	}

	public class ReceiverThread extends Thread {

		private static final int DEFAULT = 0;

		private boolean isRunning = false;

		private ServerSocket socketR;

		private BufferedReader entry;

		private DataOutputStream output;

		private String msgReceive_aux = null;

		private String msgReceive = " ";

		@Override
		public void run() {

			isRunning = true;
			socketR = null;

			try {
				Socket SocketReader = null;

				socketR = new ServerSocket(SENDER_PORT);
				while (isRunning) {
					SocketReader = socketR.accept();

					entry = new BufferedReader(new InputStreamReader(
							SocketReader.getInputStream()));

					// output = new
					// DataOutputStream(SocketReader.getOutputStream());

					msgReceive_aux = entry.readLine();

					while (msgReceive_aux != null) {
						msgReceive.concat(msgReceive_aux);
						msgReceive_aux = entry.readLine();
					}
					entry.close();
					msgReceive_aux = null;

					receivedMessageType(msgReceive);

					msgReceive = " ";

				}

			} catch (UnknownHostException e) {
				// isConnected = false;
				e.printStackTrace();
			} catch (IOException e) {
				// isConnected = false;
				e.printStackTrace();
			}
		}

		private Object receivedMessageType(String msgReceive) {

			char[] aux = null;
			String IpSender;
			// char [] NameSender = null;
			String NameSender;
			// char [] IprReceiver = null;
			String IpReceiver;
			// char [] NameReceiver = null;
			String NameReceiver;
			// char [] Type = null;
			int Type;
			String Data;

			if (msgReceive != null) {
				// handle Ipsender
				msgReceive.getChars(
						msgReceive.indexOf("IdentificationSender: ") + 22,
						msgReceive.indexOf("/#/") - 1, aux, 0);
				IpSender = new String(aux);
				aux = null;

				// handle Namesender
				msgReceive.getChars(msgReceive.indexOf("/#/") + 3,
						msgReceive.indexOf("||") - 1, aux, 0);
				NameSender = new String(aux);
				aux = null;
				Log.d("SENDER", " " + IpSender + " -> " + NameSender);
				// handle IpReceiver
				msgReceive.getChars(
						msgReceive.indexOf("IdentificationDestiny: ") + 24,
						msgReceive.indexOf("//#//") - 1, aux, 0);
				IpReceiver = new String(aux);
				aux = null;

				// handle NameReceiver
				msgReceive.getChars(msgReceive.indexOf("//#//") + 5,
						msgReceive.indexOf("|||") - 1, aux, 0);
				NameReceiver = new String(aux);
				aux = null;
				Log.d("RECEIVER", " " + IpReceiver + " -> " + NameReceiver);

				// handle type
				msgReceive.getChars(msgReceive.indexOf("Type: ") + 6,
						msgReceive.indexOf("||||") - 1, aux, 0);
				Type = Integer.parseInt(new String(aux));
				aux = null;
				Log.d("TYPE", " " + Type);

				// handle data
				// TODO How is the data stocked ? Is the recorded file in a
				// string ?
				msgReceive.getChars(msgReceive.indexOf("Data: ") + 6,
						msgReceive.indexOf(" END###!!!") - 1, aux, 0);
				Data = new String(aux);
				aux = null;

				Log.d("DATA", "data-> " + Data + " ");

				return convertToType(Data, Type);

			} else {
				Log.d("CONNECT", "Error Receiving data!!!");
				return null;

			}
		}

		@SuppressLint("NewApi")
		public Object convertToType(String Data, int Type) {
			byte[] image_byte = null;
			byte[] audio_byte = null;

			if (Type == MyMessage.MessageType.TYPE_RECORD.ordinal()) {
				audio_byte = Base64.decode(Data, Base64.DEFAULT);
				Log.d("AUDIO", "New msg receive !!!!");
				return audio_byte;
			}

			if (Type == MyMessage.MessageType.TYPE_PICTURE.ordinal()) {
				image_byte = Base64.decode(Data, Base64.DEFAULT);

				Bitmap decodedByte = BitmapFactory.decodeByteArray(image_byte, 0, image_byte.length);
				String path = Environment.getExternalStorageDirectory().toString();
				OutputStream fOut = null;
				File file = new File(path,"ReceivedPicture"+".jpg");
				//fOut = new FileOutputStream(file);
				//MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());				
				

		//		Bitmap decodedByte = BitmapFactory.decodeByteArray(image_byte,
			//			0, image_byte.length);
			//	saveToCacheFile(decodedByte);

				// String path =
				// Environment.getExternalStorageDirectory().toString();
				// OutputStream fOut = null;
				// File file = new File(path,"ReceivedPicture"+".jpg");
				// fOut = new FileOutputStream(file);
				// MediaStore.Images.Media.insertImage(getContentResolver(),
				// file.getAbsolutePath(), file.getName(), file.getName());
				Log.d("IMAGE", "New msg receive !!!!");
				return decodedByte;
			}

			if (Type == MyMessage.MessageType.TYPE_TEXT.ordinal()) {
				Log.d("TXT", "New msg receive !!!!");
				return Data;
			}
			return null;
		}
	}

	public static void saveToCacheFile(Bitmap bmp) {
		File f = Environment.getExternalStorageDirectory();
		String path = f.getAbsolutePath() + "/cache.png";
		saveToFile(path, bmp);
	}

	public static void saveToFile(String filename, Bitmap bmp) {
		try {
			FileOutputStream out = new FileOutputStream(filename);
			bmp.compress(CompressFormat.PNG, 100, out);
			out.flush();
			out.close();
		} catch (Exception e) {
			Log.e(TAG, "Cannot save file !");
		}
	}

	// Why don't send the text without putting it in a file ?
	public static File writeStrToFile(String msg) {
		FileWriter fileWriter = null;
		File newTextFile = null;
		try {
			String content = msg;
			newTextFile = new File(FILE_PATH);
			fileWriter = new FileWriter(newTextFile);
			fileWriter.write(content);
			fileWriter.close();
		} catch (IOException ex) {
			Log.d("ERROR", "Msg de erro: " + ex.getMessage());
		} finally {
			try {
				fileWriter.close();
			} catch (IOException ex) {
				Log.d("ERROR", "Msg de erro: " + ex.getMessage());
			}
		}
		return newTextFile;
	}
}
